﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Text;
using System.IO;
using Facebook.Contracts;
using Facebook.Channels;
using Facebook.Exceptions;
using Facebook.Utils;
using System.Web.Script.Serialization;
using Social.Core;
using Social.Core.Contracts;

namespace Facebook.Services
{
    /// <summary>
    /// Provides the main funcionalities to access the facebook graph api.
    /// </summary>
    /// <remarks>
    ///  This class exposes the funcionalities available in the facebook API,  based on public methods.
    ///  Throught out this class you will find methods to access the API. 
    /// </remarks>
    public class FacebookService : IFacebookService
    {

        public FacebookService() { }
        public FacebookService(Facebookconfig config, IFacebookChannel channel) 
        {
            this.channel = channel;
            this.deserializer = config.Deserializer;
        }

        IFacebookChannel channel;
        IDeserializer deserializer;

        public IFacebookChannel Channel { get { return channel; } }

        public IDeserializer Deserializer {get{ return  deserializer; }}


        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     // gets all the metadata of the user that is logged in 
        ///     dynamic obj = fbservice.GetType("me");
        ///     // or 
        ///     FaceBookEntity obj = fbservice.GetType("me") as FacebookEntity;
        ///     string value = obj.Properties[nameOfTheProperty];
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic GetType(string graphId)
        {

            IDictionary<String,string> args = new Dictionary<string,string>();
            
            args.Add("metadata", "1");

            string result = channel.RequestGraph(graphId, args);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });

        }

        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     // Select all id and name of me friends
        ///     dynamic obj = fbservice.Select("me",ConnectionType.friends, new String[] {id, name});
        ///     // or 
        ///     FaceBookEntity obj = fbservice.Select("me",ConnectionType.friends, new String[] {id, name}) as FacebookEntity;
        ///     string value = obj.Properties[nameOfTheProperty];
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic Select(string graphId, ConnectionType? connectionType, string[] fields)
        {
            
            if (channel == null)
                throw new FacebookConfigException("No channel associated with the facebook service");

            string fieldsParam = String.Empty;

            Dictionary<String, String> selectParams = new Dictionary<string, string>(); ;

            if (fields != null)
            {
                fieldsParam = fields.ConcatToString(0, fields.Length, ',');

                selectParams.Add("fields", fieldsParam);
            }

            string result =string.Empty;
            
            if(connectionType.HasValue)
                result  = channel.RequestGraph(graphId + "/" + connectionType.ToString(), selectParams);
            else
                result = channel.RequestGraph(graphId, selectParams);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });

        }

        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     // Select all id and name of me friends
        ///     dynamic obj = fbservice.Search("me",SearchType.user, null);
        ///     // or 
        ///     FaceBookEntity obj = fbservice.Search("me",SearchType.user, null) as FacebookEntity;
        ///     string value = obj.Properties[nameOfTheProperty];
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic Search(string query, SearchType? searchtype, IDictionary<string,string> searchTypeArgs)
        {
            if (channel == null)
                throw new FacebookConfigException("No channel associated with the facebook service");

            
            IDictionary<String, String> queryStringParams = new Dictionary<string, string>() ;

            queryStringParams.Add("q", query);
            if (searchtype.HasValue)
            {
                //if(searchtype.Value == SearchType.events)
                //    queryStringParams.Add("type", searchtype.Value.ToString().Remove(searchtype.Value.ToString().Length-1));
                //else        
                    queryStringParams.Add("type", searchtype.Value.ToString());
            }
            if (searchTypeArgs != null)
            {
                queryStringParams = (IDictionary<String, String>)queryStringParams.Concat(searchTypeArgs);
            }

            string result = channel.RequestGraph("search", queryStringParams);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });
        }

        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     
        ///     FacebookEntity searchResult = fbservice.Search("text on a unique post",SearchType.post, null) as FacebookEntity;
        ///     
        ///     Dictionary&gt;string ,string  args&lt; = new Dictionary&gt;string,string&lt;();
        ///     
        ///     args.add("message","this is a comment to the post")
        ///     
        ///     FacebookEntity publishResult = fbservice.Publish(searchResult.Properties["id"],PublishType.comments, null);
        ///     
        ///     
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic Publish(string graphId, PublishType publishType, IDictionary<string, string> arguments)
        {
            string result = channel.RequestGraph(graphId + "/" + publishType.ToString(), arguments);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });
        }
        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     
        ///     FacebookEntity searchResult = fbservice.Search("text of a unique post",SearchType.post, null) as FacebookEntity;
        ///     
        ///     Dictionary<string,string>  args = new Dictionary<string,string>();
        ///     
        ///     args.add("message","this is a comment to the post")
        ///     
        ///     FacebookEntity publishResult = fbservice.Delete(searchResult.Properties["id"]);
        ///     
        ///     
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic Delete(string graphId)
        {
            IDictionary<string,string> arguments = new Dictionary<string,string>();
            arguments.Add("method","delete");
            string result = channel.RequestGraph(graphId, arguments);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });
        }

        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     
        ///     dynamic queryResult = facebookservice.QueryGraph("select id, name FROM users Where  SELECT name, fan_count  FROM page WHERE page_id=pageIdqueried ", "json");
        ///     
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic QueryGraph(string query, string format)
        {
 
            IDictionary<String, String> queryStringParams = new Dictionary<string, string>();

            queryStringParams.Add("query", query);
            queryStringParams.Add("format", format);

            string result = channel.QueryGraph(queryStringParams);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });
        }

        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     
        ///     dynamic analytics = facebookservice.GetAnalytics("application_canvas_views", "yesterday",null);
        ///     
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic GetAnalytics(string metric, string since, string until) 
        {
            string result = channel.GetInsights(metric, since, until);

            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });

        }


        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     
        ///     dynamic requestResult = facebookservice.GetPage("https://graph.facebook.com/me");
        ///     
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public dynamic GetPage(string pageurl)
        {
            string result = channel.Protocol.DoRequest(pageurl);
            return deserializer.Deserialize(result, new JavaScriptConverter[] { new FBJsonConverter() });
        }


        /// <example>
        ///     
        ///     IFacebookService fbservice = new FacebookService(config, channel);
        ///     
        ///     string url = facebookservice.GetPicture("me");
        ///     
        /// </example>
        /// <see cref="Facebook.Contracts.IFacebookService"/>
        public string GetPicture(string graphId)
        {
            return string.Format(channel.Config.ActionUrl, graphId + "/picture");
        }
    }


  
}